/**
 * SSD1306 OLED Display Driver
 */

#include "ssd1306.h"
#include <string.h>
#include <stdio.h>
#include <tgmath.h>
#include <math.h>


// SSD1306 显示缓冲区
static uint8_t displayBuffer[SSD1306_BUFFER_SIZE];
static I2C_HandleTypeDef *ssd1306_i2c_handle;
static uint8_t ssd1306_addr = SSD1306_I2C_ADDR; // 7-bit 地址，默认0x3C
static uint8_t cursor_x, cursor_y;

/**
 * 向SSD1306发送命令
 */
static void SSD1306_WriteCommand(uint8_t command)
{
    uint8_t data[2] = {SSD1306_COMMAND, command};
    HAL_I2C_Master_Transmit(ssd1306_i2c_handle, ssd1306_addr << 1, data, 2, 100);
}

/**
 * 向SSD1306发送数据
 */
static void SSD1306_WriteData(uint8_t *data, uint16_t size)
{
    uint8_t buffer[size + 1];
    buffer[0] = SSD1306_DATA;
    memcpy(buffer + 1, data, size);
    HAL_I2C_Master_Transmit(ssd1306_i2c_handle, ssd1306_addr << 1, buffer, size + 1, 100);
}

/**
 * 初始化SSD1306 OLED显示屏
 */
uint8_t SSD1306_Init(I2C_HandleTypeDef *hi2c)
{
    ssd1306_i2c_handle = hi2c;

    // 尝试多次探测I2C地址，增加超时时间
    uint8_t addr_found = 0;

    // 尝试0x3C地址
    for (int i = 0; i < 5; i++) {
        if (HAL_I2C_IsDeviceReady(ssd1306_i2c_handle, (0x3C << 1), 3, 200) == HAL_OK) {
            ssd1306_addr = 0x3C;
            addr_found = 1;
            break;
        }
        HAL_Delay(10);
    }

    // 如果0x3C失败，尝试0x3D
    if (!addr_found) {
        for (int i = 0; i < 5; i++) {
            if (HAL_I2C_IsDeviceReady(ssd1306_i2c_handle, (0x3D << 1), 3, 200) == HAL_OK) {
                ssd1306_addr = 0x3D;
                addr_found = 1;
                break;
            }
            HAL_Delay(10);
        }
    }

    if (!addr_found) {
        return 1; // 未找到设备
    }

    // 最简单的SSD1306初始化序列
    SSD1306_WriteCommand(0xAE); // 显示关闭
    HAL_Delay(10);

    // 核心修改：配置显示方向（行+列反转，实现180度显示）
    SSD1306_WriteCommand(0xC8);        // 反转行扫描方向（解决上下颠倒）
    SSD1306_WriteCommand(0xA1);        // 反转列扫描方向（解决左右镜像）
    // SSD1306_WriteCommand(0xC0);        // 反转行扫描方向（解决上下颠倒）
    // SSD1306_WriteCommand(0xA0);        // 反转列扫描方向（解决左右镜像）

    SSD1306_WriteCommand(0x20);        // 设置显存寻址模式
    // SSD1306_WriteCommand(0x00);        // 水平寻址（必须与UpdateScreen逻辑匹配）
    SSD1306_WriteCommand(0x02);        // 页寻址模式（滚屏命令生效）

    SSD1306_WriteCommand(0x8D); // 电荷泵
    SSD1306_WriteCommand(0x14); // 电荷泵开启

    SSD1306_WriteCommand(0x81); // 对比度
    SSD1306_WriteCommand(0xFF); // 最大对比度

    SSD1306_WriteCommand(0xA4); // 正常显示
    SSD1306_WriteCommand(0xA6); // 正常显示

    SSD1306_WriteCommand(0xAF); // 显示开启

    HAL_Delay(100);

    SSD1306_Clear();
    SSD1306_UpdateScreen();

    return 0;
}

/**
 * 打开显示
 */
void SSD1306_DisplayOn(void)
{
    SSD1306_WriteCommand(SSD1306_DISPLAYON);
}

/**
 * 关闭显示
 */
void SSD1306_DisplayOff(void)
{
    SSD1306_WriteCommand(SSD1306_DISPLAYOFF);
}

/**
 * 清空屏幕
 */
void SSD1306_Clear(void)
{
    memset(displayBuffer, 0, sizeof(displayBuffer));
    cursor_x = 0;
    cursor_y = 0;
}

/**
 * 更新屏幕显示
 */
void SSD1306_UpdateScreen(void)
{
    // SSD1306水平寻址模式
    for (uint8_t i = 0; i < 8; i++) {
        SSD1306_WriteCommand(0xB0 + i);  // 页地址
        SSD1306_WriteCommand(0x00);      // 列地址低4位
        SSD1306_WriteCommand(0x10);      // 列地址高4位
        SSD1306_WriteData(&displayBuffer[SSD1306_WIDTH * i], SSD1306_WIDTH);
    }
}

/**
 * 绘制像素点
 */
void SSD1306_DrawPixel(uint8_t x, uint8_t y, uint8_t color)
{
    if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) {
        return;
    }

    if (color) {
        displayBuffer[x + (y / 8) * SSD1306_WIDTH] |= 1 << (y % 8);
    } else {
        displayBuffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8));
    }
}

/**
 * 填充屏幕
 */
void SSD1306_Fill(uint8_t color)
{
    memset(displayBuffer, color ? 0xFF : 0x00, sizeof(displayBuffer));
}

/**
 * 设置光标位置
 */
void SSD1306_SetCursor(uint8_t x, uint8_t y)
{
    cursor_x = x;
    cursor_y = y;
}


/**
 * 反显显示
 */
void SSD1306_InvertDisplay(void)
{
    SSD1306_WriteCommand(SSD1306_INVERTDISPLAY);
}

/**
 * 正常显示
 */
void SSD1306_NormalDisplay(void)
{
    SSD1306_WriteCommand(SSD1306_NORMALDISPLAY);
}

/**
 * 全亮显示（不依赖显存）
 */
void SSD1306_AllOn(void)
{
    SSD1306_WriteCommand(SSD1306_DISPLAYALLON); // 0xA5
}









/**
 * 显示单个8×16字符（支持不清屏，用于字符串叠加）
 * @param x          字符X坐标
 * @param y          字符Y坐标
 * @param charData   8×16点阵数据
 * @param clearScreen 是否清屏（1=清屏，0=不清屏）
 */
void SSD1306_ShowCustomChar(uint8_t x, uint8_t y, const uint8_t *charData, uint8_t clearScreen)
{
    if (charData == NULL) return;
    if (x + 8 > SSD1306_WIDTH || y + 16 > SSD1306_HEIGHT) return;

    if (clearScreen) {
        SSD1306_Clear(); // 仅单个字符显示时清屏，字符串显示时不清屏
    }

    // 以下绘制逻辑不变
    for (uint8_t col = 0; col < 8; col++) {
        uint8_t upper_data = charData[col];
        uint8_t lower_data = charData[col + 8];
        for (uint8_t row = 0; row < 8; row++) {
            if (upper_data & (0x80 >> row)) {
                SSD1306_DrawPixel(x + col, y + row, 1);
            }
        }
        for (uint8_t row = 0; row < 8; row++) {
            if (lower_data & (0x80 >> row)) {
                SSD1306_DrawPixel(x + col, y + 8 + row, 1);
            }
        }
    }
}

/**
 * 在指定位置绘制心形,空心
 * @param x0 心形中心X坐标（建议64，屏幕中间）
 * @param y0 心形中心Y坐标（建议32，屏幕中间）
 * @param scale 缩放比例（建议3~5，值越大心形越大）
 */
void SSD1306_DrawHeart(uint8_t x0, uint8_t y0, uint8_t scale)
{
    SSD1306_Clear(); // 清屏准备绘制

    // 心形参数方程：x = 16sin³(t), y = 13cos(t) - 5cos(2t) - 2cos(3t) - cos(4t)
    // t范围：0 ~ 2π（约6.28），步长越小曲线越平滑
    for (float t = 0; t < 6.28; t += 0.01) {
        // 计算原始心形坐标（基于参数方程）
        float x = 16 * pow(sin(t), 3);
        float y = 13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t);

        // 缩放并平移到屏幕指定位置（x0,y0为中心）
        int16_t draw_x = x0 + (int16_t)(x * scale);
        int16_t draw_y = y0 - (int16_t)(y * scale); // y轴反转（屏幕y向下增大）

        // 检查坐标是否在屏幕范围内（0<=x<128, 0<=y<64）
        if (draw_x >= 0 && draw_x < SSD1306_WIDTH && draw_y >=0 && draw_y < SSD1306_HEIGHT) {
            SSD1306_DrawPixel(draw_x, draw_y, 1); // 绘制心形上的点
        }
    }

    SSD1306_UpdateScreen(); // 刷新显示
}





/**
 * 绘制标准心形心形（比例协调，无拉伸）
 * @param x0    心形中心X坐标（建议64，屏幕横向中心）
 * @param y0    心形中心Y坐标（建议32，屏幕纵向中心）
 * @param radius 心形半径（控制大小，推荐8~12，10为标准大小）
 */
void SSD1306_DrawStandardHeart(uint8_t x0, uint8_t y0, uint8_t radius)
{
    SSD1306_Clear();

    // 标准心形数学模型：基于极坐标转换，确保上下比例协调
    for (uint8_t y = 0; y < SSD1306_HEIGHT; y++) {
        for (uint8_t x = 0; x < SSD1306_WIDTH; x++) {
            // 转换为以中心为原点的相对坐标（y轴反转，因屏幕y向下增长）
            int16_t dx = x - x0;
            int16_t dy = y0 - y;  // 反转y轴，使向上为正

            // 归一化坐标半径（消除大小影响，便于形状控制）
            float nx = (float)dx / radius;
            float ny = (float)dy / radius;

            // 标准心形公式（确保证上宽下尖的经典形状）
            // 公式来源：(x² + y² - 1)³ - x²y³ = 0（内部点满足 ≤0）
            float x2 = nx * nx;
            float y2 = ny * ny;
            float term1 = pow(x2 + y2 - 1.0f, 3.0f);  // (x²+y²-1)³
            float term2 = x2 * pow(ny, 3.0f);          // x²y³
            if (term1 - term2 <= 0.0f) {  // 满足条件即为心形内部点
                SSD1306_DrawPixel(x, y, 1);
            }
        }
    }

    SSD1306_UpdateScreen();
}





/**
 * 实心心形从上到下逐步显示（动画效果）
 * @param x0       心形中心X坐标（建议64）
 * @param y0       心形中心Y坐标（建议32）
 * @param radius   心形大小（推荐10）
 * @param stepDelay 每显示一行的延迟（ms，控制越大动画越慢，建议5~20）
 */
void SSD1306_HeartBeatAnimation(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t stepDelay)
{
    SSD1306_Clear();
    SSD1306_UpdateScreen();  // 先清屏

    // 逐行显示：从屏幕顶部（y=0）到心形底部（y=63）
    for (uint8_t currentY = 0; currentY < SSD1306_HEIGHT; currentY++) {
        // 绘制当前行及以上的所有心形像素（实现“逐步向下”）
        for (uint8_t y = 0; y <= currentY; y++) {  // 只绘制到currentY行
            for (uint8_t x = 0; x < SSD1306_WIDTH; x++) {
                // 计算相对坐标（归一化）
                int16_t dx = x - x0;
                int16_t dy = y0 - y;  // y轴反转（向上为正）
                float nx = (float)dx / radius;
                float ny = (float)dy / radius;

                // 标准心形公式判断是否为内部点
                float x2 = nx * nx;
                float y2 = ny * ny;
                float term1 = pow(x2 + y2 - 1.0f, 3.0f);
                float term2 = x2 * pow(ny, 3.0f);

                if (term1 - term2 <= 0.0f) {  // 心形内部点
                    SSD1306_DrawPixel(x, y, 1);
                }
            }
        }

        SSD1306_UpdateScreen();  // 刷新当前帧
        HAL_Delay(stepDelay);    // 延时，控制动画速度
    }
}

// 完全保留你确认正确的镜像修复逻辑，仅将旋转方向改为顺时针90度
// 数据排列从左到右，从上到下，取模方式：横向八点右高位
void SSD1306_ShowChinese16x16(uint8_t x, uint8_t y, const uint8_t *hanzi, uint8_t clear)
{
    if (hanzi == NULL) return;
    if (x + 16 > 128 || y + 16 > 64) return;
    if (clear) SSD1306_Clear();

    // 【原始正确的镜像修复逻辑，100%不变】
    for (uint8_t col = 0; col < 16; col++) {
        uint8_t orig_col = 15 - col; // 你确认正确的镜像修复：列反转

        uint8_t upper8 = hanzi[orig_col * 2];
        uint8_t lower8 = hanzi[orig_col * 2 + 1];

        // 【仅修改旋转方向为顺时针90度，其他完全不变】
        // 上8行绘制（顺时针旋转）
        for (uint8_t bit = 0; bit < 8; bit++) {
            uint8_t orig_row = bit;
            if (upper8 & (1 << bit)) {
                // 顺时针旋转90度坐标公式（修正方向）
                uint8_t rot_x = x + orig_row;       // 原始行直接映射到x
                uint8_t rot_y = y + (15 - col);     // 原始列反向映射到y
                SSD1306_DrawPixel(rot_x, rot_y, 1); // 仅修改此处坐标
            }
        }

        // 下8行绘制（顺时针旋转）
        for (uint8_t bit = 0; bit < 8; bit++) {
            uint8_t orig_row = 8 + bit;
            if (lower8 & (1 << bit)) {
                // 顺时针旋转90度坐标公式（修正方向）
                uint8_t rot_x = x + orig_row;
                uint8_t rot_y = y + (15 - col);
                SSD1306_DrawPixel(rot_x, rot_y, 1); // 仅修改此处坐标
            }
        }
    }

    SSD1306_UpdateScreen();
}




/**
 * 水平滚动（左滚/右滚）
 * @param dir   0：右滚（0x26），1：左滚（0x27）
 * @param start_page 起始页（0~7）
 * @param end_page   结束页（0~7，需 ≥ start_page）
 * @param interval   滚动间隔（0~7，对应上述参数）
 */
void SSD1306_HorizontalScroll(uint8_t dir, uint8_t start_page, uint8_t end_page, uint8_t interval)
{
    SSD1306_WriteCommand(0x2E); // 先关闭已有滚动

    // 发送滚动方向命令
    SSD1306_WriteCommand(dir ? 0x27 : 0x26);
    // 发送参数：起始页、间隔、结束页、填充位
    SSD1306_WriteCommand(0x00);          // 填充位（固定0x00）
    SSD1306_WriteCommand(start_page);    // 起始页
    SSD1306_WriteCommand(interval);      // 滚动间隔
    SSD1306_WriteCommand(end_page);      // 结束页
    SSD1306_WriteCommand(0x00);          // 填充位（固定0x00）
    SSD1306_WriteCommand(0xFF);          // 填充位（固定0xFF）

    SSD1306_WriteCommand(0x2F); // 开启滚动
}